package it.softphone.cmc.event.client;

import java.util.logging.Level;

import com.google.gwt.appengine.channel.client.Channel;
import com.google.gwt.appengine.channel.client.ChannelFactory;
import com.google.gwt.appengine.channel.client.ChannelFactory.ChannelCreatedCallback;
import com.google.gwt.appengine.channel.client.SocketError;
import com.google.gwt.appengine.channel.client.SocketListener;
import com.google.gwt.core.client.GWT;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.user.client.rpc.AsyncCallback;


/**
 * 
 * @author softphone
 *
 */
public class EventManager {
	
	static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(EventManager.class.getName());
	
	
	private static final String TOKEN_SERVICE = "rest/service/events/token";

	public static abstract class Listener  {

		public abstract void onEvent( String event );
		
		public void onError(Throwable t) {
		}
		
		public void onClose() {
			
		}
		
	}
	
	private static final java.util.List<Listener> listenerList = new java.util.ArrayList<Listener>(10); 
	
	
	public static final void addListener( Listener l ) {
		if( l !=null ) {
			
			listenerList.add(l);
		}
	}
	
	public static final void removeListener( Listener l ) {
		if( l !=null ) {
			
			listenerList.remove(l);
		}
	}
	
	protected static final void sendEvent( String event ) {
		for( Listener l : listenerList ) l.onEvent(event);
	}
	protected static final void sendError( Throwable t ) {
		for( Listener l : listenerList ) l.onError(t);
	}
	protected static final void sendClose() {
		for( Listener l : listenerList ) l.onClose();
	}

    static public void initEventsManagement( String user, String password, final AsyncCallback<String> callback ) {
		RequestBuilder request = new RequestBuilder(RequestBuilder.GET, GWT.getModuleBaseURL() + TOKEN_SERVICE);
		
		request.setUser(user);
		request.setPassword(password);
		
		try {
			request.sendRequest(null,new RequestCallback() {
				
				@Override
				public void onResponseReceived(Request req, Response res) {
					logger.info("onResponseReceived " + res.getText() );
					
					registerChannel(res.getText());
					
					if( callback != null ) callback.onSuccess(res.getText());
					
				}
				
				@Override
				public void onError(Request req, Throwable t) {
					logger.log( Level.WARNING, "onError ", t );
					
					if( callback != null ) callback.onFailure(t);
				}
			});
		} catch (RequestException e) {

			logger.log( Level.WARNING, "fail request token ", e );
		}
   	
    }
	
    /**
     * 
     * @param domain domain url - MUST non end with '/' char
     */
    static public void initCrossDomainEventsManagement( String user, String password, final String domain, final AsyncCallback<String> callback ) {
    	if( null == domain ) throw new IllegalArgumentException("domain is null");
    	
		RequestBuilder request = new RequestBuilder(RequestBuilder.GET, GWT.getModuleBaseURL() + TOKEN_SERVICE);
		
		request.setUser(user);
		request.setPassword(password);
		
		try {
			request.sendRequest(null,new RequestCallback() {
				
				@Override
				public void onResponseReceived(Request req, Response res) {
					logger.info("onResponseReceived " + res.getText() );
					
					registerCrossDomainChannel( domain, res.getText());

					if( callback != null ) callback.onSuccess(res.getText());
					
				}
				
				@Override
				public void onError(Request req, Throwable t) {
					logger.log( Level.WARNING, "onError ", t );
					
					if( callback != null ) callback.onFailure(t);
				}
			});
		} catch (RequestException e) {

			logger.log( Level.WARNING, "fail request token ", e );
		}
    	
    }
    
    static final ChannelCreatedCallback internalChannelCallback = new ChannelCreatedCallback() {
		  @Override
		  public void onChannelCreated(Channel channel) {
		    channel.open(new SocketListener() {
		      @Override
		      public void onOpen() {
		        logger.info("Event Channel Opened!");
		      }
		      @Override
		      public void onMessage(String message) {
		    	  logger.info("Event received: " + message);
		    	  EventManager.sendEvent(message);
		      }
		      @Override
		      public void onError(SocketError error) {
		    	  logger.info("Event error: " + error.getDescription());
		    	  EventManager.sendError( new Exception( error.getDescription()) );
		      }
		      @Override
		      public void onClose() {
		    	  logger.info("Event Channel Closed!");
		    	  EventManager.sendClose();
		      }
		    });
		  }
		};		

	private static void registerCrossDomainChannel( String domain, String token ) {

		CrossDomainChannelFactory.createChannel(domain, token, internalChannelCallback );
	}
   
	private static void registerChannel( String token ) {

			
		ChannelFactory.createChannel(token, internalChannelCallback );
	}
	
}